package com.futao.springsecuritylearn.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.time.Duration;

/**
 * @author ft
 * @date 2021/5/18
 */
@Configuration
public class UserNamePwdConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 设置登录的用户名密码
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
//        String password = passwordEncoder.encode("nobug666.");
//        auth.inMemoryAuthentication()
//                .withUser("futao")
//                .password(password)
//                .roles("admin");


        // 配置类的方式设置用户名密码
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private DataSource dataSource;

    /**
     * RememberMe的配置
     *
     * @return
     */
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setCreateTableOnStartup(true);
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                // 没有权限的跳转页面
                .accessDeniedPage("/unauth.html");
        // 关于登录与权限
        http.formLogin()
                    // 自定义登录页面
                    .loginPage("/login.html")
                    // 登录提交的api地址，但是会转为SpringSecurity实现
                    .loginProcessingUrl("/user/login")
                    // 登录成功之后的跳转地址
                    .defaultSuccessUrl("/test/index").permitAll()
                .and()
                    //配置某些路径不需要登录
                    .authorizeRequests()
                    .antMatchers("/test/hello", "/user/login").permitAll()
                    // 唯一权限
                    //.antMatchers("/test/index").hasAuthority("admins")
                    // 任一权限
                    //.antMatchers("/test/index").hasAnyAuthority("admins", "manager")
                    // 这种写法会加前缀 ROLE_amdins
                    //.antMatchers("/test/index").hasRole("amdins")
                    //.antMatchers("/test/index").hasAnyRole("amdins", "manage")
                    .anyRequest().authenticated()
                //记住我
                .and()
                    .rememberMe()
                    .tokenRepository(persistentTokenRepository())
                    .tokenValiditySeconds((int) Duration.ofDays(7).getSeconds())
                    .userDetailsService(userDetailsService)
                // 关闭csrf保护
                .and()
                    .csrf()
                    .disable();

        // 关于登出
        http.logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/test/hello")
                .permitAll();
    }
}
